package com.jxtc.enterprise.tenant.service;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jxtc.enterprise.common.constants.DeliveryCostTypeEnum;
import com.jxtc.enterprise.common.constants.MealTypeEnum;
import com.jxtc.enterprise.common.entity.*;
import com.jxtc.enterprise.common.exception.ModifyFailureException;
import com.jxtc.enterprise.common.mapper.*;
import com.jxtc.enterprise.common.service.DeliveryTaskTemplateStoreService;
import com.jxtc.enterprise.common.utils.CurrencyUtil;
import com.jxtc.enterprise.common.utils.DateTimeUtil;
import com.jxtc.enterprise.common.vo.PaginationResponseVO;
import com.jxtc.enterprise.tenant.dto.deliveryTaskTemplate.DeliveryCostDTO;
import com.jxtc.enterprise.tenant.dto.deliveryTaskTemplate.DeliveryTaskCreateDTO;
import com.jxtc.enterprise.tenant.dto.deliveryTaskTemplate.DeliveryTaskInfoDTO;
import com.jxtc.enterprise.tenant.dto.deliveryTaskTemplate.DeliveryTaskUpdateDTO;
import com.jxtc.enterprise.tenant.vo.deliveryTask.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
@Slf4j
public class TenantDeliveryTaskManageService {

    private final DeliveryTaskTemplateMapper deliveryTaskTemplateMapper;
    private final DeliveryTaskTemplateStoreService deliveryTaskTemplateStoreService;
    private final CompanyMapper companyMapper;
    private final StoreMapper storeMapper;
    private final RiderMapper riderMapper;
    private final FoodMenuMapper foodMenuMapper;
    private final DeliveryTaskMapper deliveryTaskMapper;
    private final DeliveryTaskStoreMapper deliveryTaskStoreMapper;


    public PaginationResponseVO<DeliveryTaskInfoVO> pageDeliveryTaskByKeyword(String keyword, String tenantId, int pageNo, int pageSize) {
        Page<DeliveryTaskInfoDTO> page = new Page<>(pageNo, pageSize);
        Page<DeliveryTaskInfoDTO> result = deliveryTaskTemplateMapper.pageDeliveryTaskByKeyword(page, keyword, tenantId);
        List<DeliveryTaskInfoVO> records = result.getRecords().stream()
                .map(this::buildDeliveryTaskInfoVO)
                .collect(Collectors.toList());
        return new PaginationResponseVO<>(result.getTotal(), result.getCurrent(), records);
    }

    private DeliveryTaskInfoVO buildDeliveryTaskInfoVO(DeliveryTaskInfoDTO dto) {
        DeliveryTaskInfoVO vo = new DeliveryTaskInfoVO();
        vo.setTaskTemplateId(dto.getTaskId());
        vo.setRiderId(dto.getRiderId());
        vo.setRiderName(dto.getRiderName());
        vo.setRiderPhone(dto.getRiderPhone());
        vo.setRiderPassword(dto.getRiderPassword());
        vo.setDeliveryTime(dto.getDeliveryTime());
        vo.setCompanyName(dto.getCompanyName());

        String mealTypeCn = MealTypeEnum.getMealTypeEnumByNameEn(dto.getMealType()).getMealTypeCn();
        vo.setMealType(mealTypeCn);

        List<String> storeNames = new ArrayList<>();
        if (dto.getStoreNames() != null) {
            // 将店铺名称按 "," 分割成店铺名称列表
            storeNames = Arrays.stream(dto.getStoreNames().split(","))
                    .collect(Collectors.toList());
        }
        vo.setStoreNames(storeNames);


        // 根据配送费用类型，构造不同格式的配送费用字符串
        String deliveryCost = formattedDeliveryCost(dto.getDeliveryCostType(), dto.getDeliveryCostValue());
        vo.setDeliveryCost(deliveryCost);
        return vo;
    }

    /**
     * 根据配送费用类型，构造不同格式的配送费用字符串
     *
     * @param deliveryCostType  配送费用类型名称
     * @param deliveryCostValue 配送费用数值，当表示金额是单位为 "分"
     * @return 配送费用
     */
    private String formattedDeliveryCost(String deliveryCostType, int deliveryCostValue) {
        if (DeliveryCostTypeEnum.PER_ORDER.getName().equals(deliveryCostType)) {
            String costInYuan = CurrencyUtil.fenToYuan(deliveryCostValue);
            return "每单" + costInYuan + "元";
        } else if (DeliveryCostTypeEnum.PERCENTAGE_OF_ORDER.getName().equals(deliveryCostType)) {
            // 百分比抽成则需要将单位由 "万分之一" 转换为 "百分之一"，即除以 100
            String percentage = new BigDecimal(deliveryCostValue)
                    .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)
                    .toString();
            return "每单抽" + percentage + "%";
        } else {
            String costInYuan = CurrencyUtil.fenToYuan(deliveryCostValue);
            return costInYuan + "元包干";
        }
    }


    public DeliveryTaskDetailVO getDeliveryTaskById(String taskId) {
        DeliveryTaskTemplate deliveryTaskTemplate = deliveryTaskTemplateMapper.selectById(taskId);
        if (deliveryTaskTemplate == null) {
            throw new IllegalArgumentException("ID 为 " + taskId + " 的配送任务不存在");
        }

        Company company = companyMapper.selectById(deliveryTaskTemplate.getCompanyId());

        // SELECT store_id FROM delivery_task_store WHERE delivery_task_id = #{taskId} AND del_flag = 0
        LambdaQueryWrapper<DeliveryTaskTemplateStore> queryWrapper = new LambdaQueryWrapper<DeliveryTaskTemplateStore>()
                .eq(DeliveryTaskTemplateStore::getTaskTemplateId, taskId)
                .eq(DeliveryTaskTemplateStore::getDelFlag, false)
                .select(DeliveryTaskTemplateStore::getStoreId);
        List<String> storeIds = deliveryTaskTemplateStoreService.listObjs(queryWrapper);

        List<StoreIdWithNameVO> storeList = new ArrayList<>();
        if (storeIds != null && !storeIds.isEmpty()) {
            List<Store> stores = storeMapper.selectBatchIds(storeIds);
            storeList = stores.stream()
                    .map(store -> new StoreIdWithNameVO(store.getId(), store.getName()))
                    .collect(Collectors.toList());
        }

        return buildDeliveryTaskDetailVO(deliveryTaskTemplate, company.getName(), storeList);
    }

    private DeliveryTaskDetailVO buildDeliveryTaskDetailVO(DeliveryTaskTemplate deliveryTaskTemplate, String companyName, List<StoreIdWithNameVO> storeList) {
        DeliveryTaskDetailVO vo = new DeliveryTaskDetailVO();
        vo.setTaskTemplateId(deliveryTaskTemplate.getId());
        vo.setDeliveryTime(deliveryTaskTemplate.getDeliveryStartTime());
        vo.setRiderId(deliveryTaskTemplate.getRiderId());
        vo.setCompanyId(deliveryTaskTemplate.getCompanyId());
        vo.setDeliveryOrder(deliveryTaskTemplate.getDeliveryOrder());

        DeliveryCostDTO deliveryCost = new DeliveryCostDTO();
        deliveryCost.setType(deliveryTaskTemplate.getDeliveryCostType());
        // 根据配送费用类型进行单位换算
        if (DeliveryCostTypeEnum.PER_ORDER.getName().equals(deliveryTaskTemplate.getDeliveryCostType())
                || DeliveryCostTypeEnum.FIXED_AMOUNT.getName().equals(deliveryTaskTemplate.getDeliveryCostType())) {
            // 如果配送费用类型为 "每单结算" 或 "固定金额包干"，则将金额单位由 "分" 转换成 "元"
            String costInYuan = CurrencyUtil.fenToYuan(deliveryTaskTemplate.getDeliveryCostValue());
            deliveryCost.setValue(costInYuan);
        } else {
            // 百分比抽成则需要将单位由 "万分之一" 转换为 "百分之一"，即除以 100
            String percentage = new BigDecimal(deliveryTaskTemplate.getDeliveryCostValue())
                    .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)
                    .toString();
            deliveryCost.setValue(percentage);
        }
        vo.setDeliveryCost(deliveryCost);

        vo.setCompanyName(companyName);
        vo.setStoreList(storeList);

        String mealTypeEn = deliveryTaskTemplate.getMealType();
        vo.setMealTypeCn(MealTypeEnum.getMealTypeEnumByNameEn(mealTypeEn).getMealTypeCn());
        vo.setMealTypeEn(mealTypeEn);

        return vo;
    }


    @Transactional(rollbackFor = {ModifyFailureException.class})
    public void addDeliveryTask(String tenantId, DeliveryTaskCreateDTO dto) {
        DeliveryTaskTemplate deliveryTaskTemplate = new DeliveryTaskTemplate();
        deliveryTaskTemplate.setTenantId(tenantId);
        deliveryTaskTemplate.setRiderId(dto.getRiderId());
        deliveryTaskTemplate.setCompanyId(dto.getCompanyId());

        String deliveryTime = dto.getDeliveryTime();
        // 如果前端传递过来的时间格式为 HH:mm，则补上 ":00"，数据库中统一保存 HH:mm:ss 格式时间
        if (deliveryTime.length() == 5) {
            deliveryTime += ":00";
        }
        deliveryTaskTemplate.setDeliveryStartTime(deliveryTime);

        boolean validDeliveryCostType = DeliveryCostTypeEnum.names().contains(dto.getDeliveryCost().getType());
        if (!validDeliveryCostType) {
            String validNames = String.join(", ", DeliveryCostTypeEnum.names());
            throw new IllegalArgumentException("无效的配送费类型，合法的配送费用类型如下: " + validNames);
        }

        deliveryTaskTemplate.setDeliveryCostType(dto.getDeliveryCost().getType());

        // 根据不同的配送费用结算方式，将结算的值转换成合理的单位（金额由 "元" -> "分"）
        int deliveryCostValue = getDeliveryCostValue(dto.getDeliveryCost());
        deliveryTaskTemplate.setDeliveryCostValue(deliveryCostValue);

        deliveryTaskTemplate.setDeliveryOrder(dto.getDeliveryOrder());

        String mealTypeEn = dto.getMealType();
        // 判断前端传递过来的用餐时段是否合法，即是否在定义的枚举中存在
        Optional<MealTypeEnum> mealTypeEnumOptional = Arrays.stream(MealTypeEnum.values())
                .filter(mealType -> mealType.getMealTypeEn().equals(mealTypeEn))
                .findAny();
        if (!mealTypeEnumOptional.isPresent()) {
            // 如果前端传递过来的用餐时段不合法，则向前端返回错误提示信息
            throw new IllegalArgumentException("无效的用餐时段，请检查用餐时段是否正确");
        }
        deliveryTaskTemplate.setMealType(mealTypeEn);

        // 保存配送任务，如果保存失败，回滚并向前端返回错误提示信息
        int insertCount = deliveryTaskTemplateMapper.insert(deliveryTaskTemplate);
        if (insertCount != 1) {
            throw new ModifyFailureException("新增配送任务失败，请联系管理员排查");
        }

        // 获取新增配送任务后自动生成的配送任务 ID，构造配送任务模板与取餐店铺关联关系
        String taskTemplateId = deliveryTaskTemplate.getId();
        List<DeliveryTaskTemplateStore> deliveryTaskTemplateStoreList = dto.getStoreIds().stream()
                .map(storeId -> new DeliveryTaskTemplateStore(taskTemplateId, storeId))
                .collect(Collectors.toList());

        // 批量保存配送任务与取餐店铺关联信息，如果保存失败，回滚并向前端返回错误提示信息
        boolean savedBatch = deliveryTaskTemplateStoreService.saveBatch(deliveryTaskTemplateStoreList);
        if (!savedBatch) {
            throw new ModifyFailureException("批量保存配送任务店铺关联数据失败，请联系管理员排查");
        }

        // 如果创建配送任务模板时，当前时间在配送开始时间之前，立刻创建当日的配送任务
        if (isCurrentTimeBeforeDeliveryStartTime(deliveryTime)) {
            String todayDate = DateTimeUtil.getCurrentDate();
            createDeliveryTask(
                    taskTemplateId,
                    tenantId,
                    dto.getRiderId(),
                    todayDate,
                    deliveryTime,
                    dto.getDeliveryCost().getType(),
                    deliveryCostValue,
                    dto.getDeliveryOrder(),
                    dto.getStoreIds()
            );
        } else {
            // 如果创建配送任务模板时，当前时间在配送开始时间之后（包含相等的情况），则创建 "明天" 的配送任务实例
            String tomorrowDate = DateTimeUtil.getTomorrowDate();
            createDeliveryTask(
                    taskTemplateId,
                    tenantId,
                    dto.getRiderId(),
                    tomorrowDate,
                    deliveryTime,
                    dto.getDeliveryCost().getType(),
                    deliveryCostValue,
                    dto.getDeliveryOrder(),
                    dto.getStoreIds()
            );
        }
    }

    @Transactional(rollbackFor = {ModifyFailureException.class})
    public void createTodayDeliveryTask(String taskTemplateId, String tenantId, String riderId, String deliveryStartTime, String deliveryCostType, Integer deliveryCostValue, Integer deliveryOrder, List<String> storeIdList) {
        DeliveryTask deliveryTask = new DeliveryTask();
        deliveryTask.setTaskTemplateId(taskTemplateId);
        deliveryTask.setTenantId(tenantId);
        deliveryTask.setRiderId(riderId);

        // 获取今天的日期
        String currentDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        deliveryTask.setDeliveryDate(currentDate);

        deliveryTask.setDeliveryStartTime(deliveryStartTime);
        deliveryTask.setDeliveryCostType(deliveryCostType);
        deliveryTask.setDeliveryCostValue(deliveryCostValue);
        deliveryTask.setDeliveryOrder(deliveryOrder);

        int insert = deliveryTaskMapper.insert(deliveryTask);
        if (insert < 1) {
            throw new ModifyFailureException("创建配送任务失败，请联系管理员排查");
        }

        // 获取新增配送任务后自动生成的配送任务 ID
        String taskId = deliveryTask.getId();

        // 新增配送任务与取餐店铺关联关系
        for (String storeId : storeIdList) {
            DeliveryTaskStore deliveryTaskStore = new DeliveryTaskStore();
            deliveryTaskStore.setTaskId(taskId);
            deliveryTaskStore.setStoreId(storeId);
            int insertCount = deliveryTaskStoreMapper.insert(deliveryTaskStore);
            if (insertCount < 1) {
                throw new ModifyFailureException("关联配送任务与店铺失败，请联系管理员排查");
            }
        }
    }

    @Transactional(rollbackFor = {ModifyFailureException.class})
    public void createDeliveryTask(String taskTemplateId, String tenantId, String riderId, String currentDate, String deliveryStartTime, String deliveryCostType, Integer deliveryCostValue, Integer deliveryOrder, List<String> storeIdList) {
        DeliveryTask deliveryTask = new DeliveryTask();
        deliveryTask.setTaskTemplateId(taskTemplateId);
        deliveryTask.setTenantId(tenantId);
        deliveryTask.setRiderId(riderId);
        deliveryTask.setDeliveryDate(currentDate);

        deliveryTask.setDeliveryStartTime(deliveryStartTime);
        deliveryTask.setDeliveryCostType(deliveryCostType);
        deliveryTask.setDeliveryCostValue(deliveryCostValue);
        deliveryTask.setDeliveryOrder(deliveryOrder);

        int insert = deliveryTaskMapper.insert(deliveryTask);
        if (insert < 1) {
            throw new ModifyFailureException("创建配送任务失败，请联系管理员排查");
        }

        // 获取新增配送任务后自动生成的配送任务 ID
        String taskId = deliveryTask.getId();

        // 新增配送任务与取餐店铺关联关系
        for (String storeId : storeIdList) {
            DeliveryTaskStore deliveryTaskStore = new DeliveryTaskStore();
            deliveryTaskStore.setTaskId(taskId);
            deliveryTaskStore.setStoreId(storeId);
            int insertCount = deliveryTaskStoreMapper.insert(deliveryTaskStore);
            if (insertCount < 1) {
                throw new ModifyFailureException("关联配送任务与店铺失败，请联系管理员排查");
            }
        }
    }

    /**
     * 判断当前时间是否在配送开始时间之前
     *
     * @param deliveryStartTime 配送开始时间，HH:mm:ss 格式字符串
     * @return 如果在配送开始时间之前，则返回 true，否则返回 false
     */
    private boolean isCurrentTimeBeforeDeliveryStartTime(String deliveryStartTime) {
        // 检查配送开始时间是否为空
        if (deliveryStartTime == null || deliveryStartTime.isEmpty()) {
            throw new IllegalArgumentException("配送开始时间不能为空");
        }
        // 解析配送开始时间
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
        LocalTime deliveryStart = LocalTime.parse(deliveryStartTime, formatter);
        log.info("currentTime: {}, deliveryStart: {}", LocalTime.now(), deliveryStart);
        // 比较当前时间是否在配送开始时间之前时间
        return LocalTime.now().isBefore(deliveryStart);
    }

    private int getDeliveryCostValue(DeliveryCostDTO deliveryCost) {
        // 根据配送费用的类型判断前端传递过来的配送费用的值是否表示"金额"
        boolean isAmountValue = DeliveryCostTypeEnum.PER_ORDER.getName().equals(deliveryCost.getType())
                || DeliveryCostTypeEnum.FIXED_AMOUNT.getName().equals(deliveryCost.getType());
        if (isAmountValue) {
            // 如果表示金额，那么存入数据库时将其单位由 "元" 转换成 "分“
            BigDecimal amount = new BigDecimal(deliveryCost.getValue());
            return CurrencyUtil.yuanToFen(amount);
        }
        // 如果表示百分比，那么将前端传递过来的 "百分之一" 转换成 "万分之一"
        // 例如：前端传递过来的值为 "3.5"，那么存入数据库时将其转换为 "3.5 * 100 = 350"
        // 注意：所有使用该字段的地方，返回给前端时需要将单位由 "万分之一" 再转换成 "百分之一"，即除以 100
        return new BigDecimal(deliveryCost.getValue()).multiply(new BigDecimal("100")).intValue();
    }


    @Transactional(rollbackFor = {ModifyFailureException.class})
    public void editDeliveryTask(DeliveryTaskUpdateDTO dto) {
        DeliveryTaskTemplate saved = deliveryTaskTemplateMapper.selectById(dto.getTaskTemplateId());
        if (saved == null) {
            throw new IllegalArgumentException("ID 为 " + dto.getTaskTemplateId() + " 的配送任务不存在");
        }
        log.info("/editDeliveryTask, 修改前的配送任务: {}", JSONObject.toJSONString(saved));

        DeliveryTaskTemplate deliveryTaskTemplate = new DeliveryTaskTemplate();
        deliveryTaskTemplate.setId(dto.getTaskTemplateId());

        String deliveryStartTime = saved.getDeliveryStartTime();
        if (dto.getDeliveryTime() != null && !dto.getDeliveryTime().isEmpty()) {
            String deliveryTime = dto.getDeliveryTime();
            // 如果前端传递过来的时间格式为 HH:mm，则补上 ":00"，数据库中统一保存 HH:mm:ss 格式时间
            if (deliveryTime.length() == 5) {
                deliveryTime += ":00";
            }
            deliveryTaskTemplate.setDeliveryStartTime(deliveryTime);
            // 更新 deliveryStartTime 变量，以便后续判断当前时间是否在配送开始时间之前
            deliveryStartTime = deliveryTime;
        }

        if (dto.getRiderId() != null && !dto.getRiderId().isEmpty()) {
            deliveryTaskTemplate.setRiderId(dto.getRiderId());
        }

        if (dto.getDeliveryCost() != null) {
            // 如果配送费用类型字段不为空; 可以尝试使用 import org.apache.commons.lang3.StringUtils 包中的 StringUtils.isNotEmpty() 方法，简化代码
            if (dto.getDeliveryCost().getType() != null && !dto.getDeliveryCost().getType().isEmpty()) {
                // 判断前端传递过来的配送费用类型是否合法，不合法时向前端返回错误提示信息
                boolean validDeliveryCostType = DeliveryCostTypeEnum.names().contains(dto.getDeliveryCost().getType());
                if (!validDeliveryCostType) {
                    String validNames = String.join(", ", DeliveryCostTypeEnum.names());
                    throw new IllegalArgumentException("无效的配送费类型，合法的配送费用类型如下: " + validNames);
                }
                deliveryTaskTemplate.setDeliveryCostType(dto.getDeliveryCost().getType());

                // 配送费用 "类型" 和 "值" 必须作为一个整体修改，否则向前端返回错误提示信息
                if (dto.getDeliveryCost().getValue() == null || dto.getDeliveryCost().getValue().isEmpty()) {
                    throw new IllegalArgumentException("配送费用类型为 " + dto.getDeliveryCost().getType() + " 时，配送费用值不能为空");
                }

                // 根据不同的配送费用结算方式，将结算的值转换成合理的单位（金额由 "元" -> "分"）
                int deliveryCostValue = getDeliveryCostValue(dto.getDeliveryCost());
                deliveryTaskTemplate.setDeliveryCostValue(deliveryCostValue);
            }
        }

        if (dto.getDeliveryOrder() != null) {
            if (dto.getDeliveryOrder() < 1) {
                throw new IllegalArgumentException("配送顺序不能小于 1");
            }
            deliveryTaskTemplate.setDeliveryOrder(dto.getDeliveryOrder());
        }

        int updateCount = deliveryTaskTemplateMapper.updateById(deliveryTaskTemplate);
        if (updateCount == 0) {
            throw new ModifyFailureException("修改配送任务失败，请联系管理员排查");
        }

        if (dto.getStoreIds() != null && !dto.getStoreIds().isEmpty()) {
            // 如果前端传递过来的与配送任务关联的店铺 ID 列表不为空，表示需要修改关联关系
            // 关联关系表 delivery_task_store 更新时可能存在的情况
            // - storeIds 中的新 ID 不在当前数据库中，需要插入
            // - 当前数据库中的 ID 不在 storeIds 中，需要进行软删除（更新 del_flag 为 1）
            // - storeIds 中的 ID 已存在但是 del_flag 为 1，则需要恢复 del_flag 为 0

            // 1. 查询当前关联数据
            // SELECT store_id FROM delivery_task_store WHERE delivery_task_id = #{taskId}
            LambdaQueryWrapper<DeliveryTaskTemplateStore> queryWrapper = new LambdaQueryWrapper<DeliveryTaskTemplateStore>()
                    .eq(DeliveryTaskTemplateStore::getTaskTemplateId, dto.getTaskTemplateId());
            List<DeliveryTaskTemplateStore> deliveryTaskTemplateStoreList = deliveryTaskTemplateStoreService.list(queryWrapper);
            List<String> existingStoreIdList = deliveryTaskTemplateStoreList.stream()
                    .map(DeliveryTaskTemplateStore::getStoreId)
                    .collect(Collectors.toList());

            // 2. 遍历 delivery_task_store 中保存的店铺 ID 列表，判断是否需要插入、更新或删除
            Set<String> toAddSet = new HashSet<>();
            Set<String> toRecoverSet = new HashSet<>();
            Set<String> toSoftDeleteSet = new HashSet<>();

            for (String storeId : dto.getStoreIds()) {
                if (!existingStoreIdList.contains(storeId)) {
                    // 如果当前关联关系不存在于数据库中，则进行插入
                    toAddSet.add(storeId);
                }
            }

            for (DeliveryTaskTemplateStore deliveryTaskTemplateStore : deliveryTaskTemplateStoreList) {
                if (dto.getStoreIds().contains(deliveryTaskTemplateStore.getStoreId())) {
                    // 如果当前关联关系存在于前端传递过来的店铺 ID 列表中
                    if (deliveryTaskTemplateStore.getDelFlag()) {
                        // 如果当前关联关系已经软删除，则恢复 del_flag 为 0
                        toRecoverSet.add(deliveryTaskTemplateStore.getStoreId());
                    }
                } else {
                    // 如果当前关联关系不存在于前端传递过来的店铺 ID 列表中，则进行软删除（更新 del_flag 为 1）
                    toSoftDeleteSet.add(deliveryTaskTemplateStore.getStoreId());
                }
            }

            // 3. 执行插入、更新和删除操作
            if (!toAddSet.isEmpty()) {
                List<DeliveryTaskTemplateStore> relationToAddList = toAddSet.stream()
                        .map(storeId -> new DeliveryTaskTemplateStore(dto.getTaskTemplateId(), storeId))
                        .collect(Collectors.toList());
                boolean savedBatch = deliveryTaskTemplateStoreService.saveBatch(relationToAddList);
                if (!savedBatch) {
                    // 如果保存失败，则抛出异常，触发回滚
                    throw new ModifyFailureException("保存配送任务与店铺关联关系失败");
                }
                log.info("/editDeliveryTask, 新增的关联店铺 ID: {}", toAddSet);
            }

            if (!toRecoverSet.isEmpty()) {
                DeliveryTaskTemplateStore deliveryTaskTemplateStore = new DeliveryTaskTemplateStore();
                deliveryTaskTemplateStore.setDelFlag(false);

                // UPDATE delivery_task_store
                // SET del_flag = 0
                // WHERE delivery_task_id = ? AND store_id IN (?, ?, ...);
                LambdaUpdateWrapper<DeliveryTaskTemplateStore> updateWrapper = new LambdaUpdateWrapper<DeliveryTaskTemplateStore>()
                        .eq(DeliveryTaskTemplateStore::getTaskTemplateId, dto.getTaskTemplateId())
                        .in(DeliveryTaskTemplateStore::getStoreId, toRecoverSet);
                boolean update = deliveryTaskTemplateStoreService.update(deliveryTaskTemplateStore, updateWrapper);
                if (!update) {
                    // 如果更新失败，则抛出异常，触发回滚
                    throw new ModifyFailureException("恢复配送任务与店铺关联关系失败");
                }
                log.info("/editDeliveryTask, 恢复的关联店铺 ID : {}", toRecoverSet);
            }

            if (!toSoftDeleteSet.isEmpty()) {
                DeliveryTaskTemplateStore deliveryTaskTemplateStore = new DeliveryTaskTemplateStore();
                deliveryTaskTemplateStore.setDelFlag(true);

                // UPDATE delivery_task_store
                // SET del_flag = 1
                // WHERE delivery_task_id = ? AND store_id IN (?, ?, ...);
                LambdaUpdateWrapper<DeliveryTaskTemplateStore> updateWrapper = new LambdaUpdateWrapper<DeliveryTaskTemplateStore>()
                        .eq(DeliveryTaskTemplateStore::getTaskTemplateId, dto.getTaskTemplateId())
                        .in(DeliveryTaskTemplateStore::getStoreId, toSoftDeleteSet);
                boolean update = deliveryTaskTemplateStoreService.update(deliveryTaskTemplateStore, updateWrapper);
                if (!update) {
                    // 如果更新失败，则抛出异常，触发回滚
                    throw new ModifyFailureException("删除配送任务与店铺关联关系失败");
                }
                log.info("/editDeliveryTask, 删除的关联店铺 ID : {}", toSoftDeleteSet);
            }
        }

        // 如果修改了配送任务模板，则需要对配送任务做如下操作：
        // 1. 如果修改配送任务模板时，当前时间在配送开始时间之前，则需要修改今天的配送任务
        // 2. 修改明天的配送任务
        // 原因如下：
        // - 新增配送任务模板时，会根据当前操作时间是否在配送开始时间（delivery_task_template_t.delivery_start_time）之前判断是立刻新增今天的配送任务实例还是明天的配送任务实例
        // - 定时任务会定期新增今天和明天的配送任务实例
        // 所以在执行更新定时任务模板操作时，需要对今天和明天的配送任务模板进行修改，今天的配送任务根据配送任务开始判断是否需要修改，而明天的配送任务一定需要修改

        // 如果修改配送任务模板时，当前时间在配送开始时间之前，则需要修改今天的配送任务
        if (isCurrentTimeBeforeDeliveryStartTime(deliveryStartTime)) {
            // 1. 删除今天的配送任务
            String currentDate = DateTimeUtil.getCurrentDate();
            LambdaQueryWrapper<DeliveryTask> queryWrapper = new LambdaQueryWrapper<DeliveryTask>()
                    .eq(DeliveryTask::getTaskTemplateId, dto.getTaskTemplateId())
                    .eq(DeliveryTask::getDeliveryDate, currentDate)
                    .eq(DeliveryTask::getDelFlag, false);
            // 每个配送任务模板每天有且仅有一个未删除的配送任务
            DeliveryTask deliveryTask = deliveryTaskMapper.selectOne(queryWrapper);
            if (deliveryTask != null) {
                softDeleteDeliveryTask(deliveryTask.getId());
            }

            // 2. 查询修改后的配送任务模板及配送任务模板与店铺的关联关系
            // 由于根据 dto 判断哪些字段被修改了，哪些字段没有被修改很麻烦，这里直接在更新后查询配送一次最新的配送任务模板数据
            DeliveryTaskTemplate latestDeliveryTaskTemplate = deliveryTaskTemplateMapper.selectById(dto.getTaskTemplateId());
            LambdaQueryWrapper<DeliveryTaskTemplateStore> queryTemplateStoreWrapper = new LambdaQueryWrapper<DeliveryTaskTemplateStore>()
                    .eq(DeliveryTaskTemplateStore::getTaskTemplateId, dto.getTaskTemplateId())
                    .eq(DeliveryTaskTemplateStore::getDelFlag, false)
                    .select(DeliveryTaskTemplateStore::getStoreId);
            List<String> storeIdList = deliveryTaskTemplateStoreService.listObjs(queryTemplateStoreWrapper);

            // 3. 创建今天的配送任务
            createDeliveryTask(
                    latestDeliveryTaskTemplate.getId(),
                    latestDeliveryTaskTemplate.getTenantId(),
                    latestDeliveryTaskTemplate.getRiderId(),
                    currentDate,
                    latestDeliveryTaskTemplate.getDeliveryStartTime(),
                    latestDeliveryTaskTemplate.getDeliveryCostType(),
                    latestDeliveryTaskTemplate.getDeliveryCostValue(),
                    latestDeliveryTaskTemplate.getDeliveryOrder(),
                    storeIdList
            );
        }

        // 修改明天的配送任务
        String tomorrowDate = DateTimeUtil.getTomorrowDate();
        LambdaQueryWrapper<DeliveryTask> queryTomorrowDeliveryTaskWrapper = new LambdaQueryWrapper<DeliveryTask>()
                .eq(DeliveryTask::getTaskTemplateId, dto.getTaskTemplateId())
                .eq(DeliveryTask::getDeliveryDate, tomorrowDate)
                .eq(DeliveryTask::getDelFlag, false);
        // 每个配送任务模板每天有且仅有一个未删除的配送任务
        DeliveryTask tomorrowDeliveryTask = deliveryTaskMapper.selectOne(queryTomorrowDeliveryTaskWrapper);
        // 如果明天的配送任务存在，才执行修改明天配送任务的逻辑
        if (tomorrowDeliveryTask != null) {
            // 删除明天的配送任务
            softDeleteDeliveryTask(tomorrowDeliveryTask.getId());

            // 查询修改后的配送任务模板及配送任务模板与店铺的关联关系
            // 由于根据 dto 判断哪些字段被修改了，哪些字段没有被修改很麻烦，这里直接在更新后查询配送一次最新的配送任务模板数据
            DeliveryTaskTemplate latestDeliveryTaskTemplate = deliveryTaskTemplateMapper.selectById(dto.getTaskTemplateId());
            LambdaQueryWrapper<DeliveryTaskTemplateStore> queryTemplateStoreWrapper = new LambdaQueryWrapper<DeliveryTaskTemplateStore>()
                    .eq(DeliveryTaskTemplateStore::getTaskTemplateId, dto.getTaskTemplateId())
                    .eq(DeliveryTaskTemplateStore::getDelFlag, false)
                    .select(DeliveryTaskTemplateStore::getStoreId);
            List<String> storeIdList = deliveryTaskTemplateStoreService.listObjs(queryTemplateStoreWrapper);
            // 创建明天的配送任务
            createDeliveryTask(
                    latestDeliveryTaskTemplate.getId(),
                    latestDeliveryTaskTemplate.getTenantId(),
                    latestDeliveryTaskTemplate.getRiderId(),
                    tomorrowDate,
                    latestDeliveryTaskTemplate.getDeliveryStartTime(),
                    latestDeliveryTaskTemplate.getDeliveryCostType(),
                    latestDeliveryTaskTemplate.getDeliveryCostValue(),
                    latestDeliveryTaskTemplate.getDeliveryOrder(),
                    storeIdList
            );
        }
    }

    @Transactional(rollbackFor = {ModifyFailureException.class})
    public void softDeleteDeliveryTask(String taskId) {
        // 1. 软删除配送任务
        DeliveryTask deliveryTask = new DeliveryTask();
        deliveryTask.setId(taskId);
        deliveryTask.setDelFlag(true);

        int updateDeliveryTaskCount = deliveryTaskMapper.updateById(deliveryTask);
        if (updateDeliveryTaskCount != 1) {
            throw new ModifyFailureException("删除配送任务失败");
        }

        // 2. 软删除配送任务与店铺的关联关系
        DeliveryTaskStore deliveryTaskStore = new DeliveryTaskStore();
        deliveryTaskStore.setDelFlag(true);
        LambdaUpdateWrapper<DeliveryTaskStore> updateWrapper = new LambdaUpdateWrapper<DeliveryTaskStore>()
                .eq(DeliveryTaskStore::getTaskId, taskId)
                .eq(DeliveryTaskStore::getDelFlag, false);
        int updateDeliveryTaskStoreCount = deliveryTaskStoreMapper.update(deliveryTaskStore, updateWrapper);
        if (updateDeliveryTaskStoreCount <= 0) {
            throw new ModifyFailureException("删除配送任务与店铺关联关系失败");
        }
    }


    @Deprecated
    @Transactional(rollbackFor = {ModifyFailureException.class})
    public void removeDeliveryTaskStoreRelation(String taskId, String storeId) {
        LambdaQueryWrapper<DeliveryTaskTemplateStore> queryWrapper = new LambdaQueryWrapper<DeliveryTaskTemplateStore>()
                .eq(DeliveryTaskTemplateStore::getTaskTemplateId, taskId)
                .eq(DeliveryTaskTemplateStore::getStoreId, storeId);

        DeliveryTaskTemplateStore savedRelation = deliveryTaskTemplateStoreService.getOne(queryWrapper);
        if (savedRelation == null) {
            throw new IllegalArgumentException("配送任务与店铺关系不存在");
        }
        log.info("/removeDeliveryTaskStoreRelation, 删除前的配送任务与店铺关联数据: {}", JSONObject.toJSONString(savedRelation));

        // 如果配送任务与店铺的关联关系已经删除，则直接返回即可，不需要做任何处理
        if (savedRelation.getDelFlag()) {
            return;
        }

        DeliveryTaskTemplateStore deliveryTaskTemplateStore = new DeliveryTaskTemplateStore();
        deliveryTaskTemplateStore.setDelFlag(true);

        LambdaUpdateWrapper<DeliveryTaskTemplateStore> updateWrapper = new LambdaUpdateWrapper<DeliveryTaskTemplateStore>()
                .eq(DeliveryTaskTemplateStore::getTaskTemplateId, taskId)
                .eq(DeliveryTaskTemplateStore::getStoreId, storeId);

        // UPDATE delivery_task_store SET del_flag = 1 WHERE delivery_task_id = ? AND store_id = ?
        boolean update = deliveryTaskTemplateStoreService.update(deliveryTaskTemplateStore, updateWrapper);
        if (!update) {
            // 如果更新失败，向前端返回错误提示信息
            throw new ModifyFailureException("移除配送任务与店铺关联失败");
        }
    }


    @Deprecated
    public void addDeliveryTaskStoreRelation(String taskId, String storeId) {
        LambdaQueryWrapper<DeliveryTaskTemplateStore> queryWrapper = new LambdaQueryWrapper<DeliveryTaskTemplateStore>()
                .eq(DeliveryTaskTemplateStore::getTaskTemplateId, taskId)
                .eq(DeliveryTaskTemplateStore::getStoreId, storeId);

        DeliveryTaskTemplateStore savedRelation = deliveryTaskTemplateStoreService.getOne(queryWrapper);
        if (savedRelation != null) {
            // 如果关联关系已存在，判断是否是未删除状态
            if (!savedRelation.getDelFlag()) {
                // 如果关联关系已存在且未删除，则不需要做任何操作
                return;
            }

            // 如果关联关系且被已删除，则将其更新为未删除状态
            DeliveryTaskTemplateStore deliveryTaskTemplateStore = new DeliveryTaskTemplateStore();
            deliveryTaskTemplateStore.setDelFlag(false);

            LambdaUpdateWrapper<DeliveryTaskTemplateStore> updateWrapper = new LambdaUpdateWrapper<DeliveryTaskTemplateStore>()
                    .eq(DeliveryTaskTemplateStore::getTaskTemplateId, taskId)
                    .eq(DeliveryTaskTemplateStore::getStoreId, storeId);

            // UPDATE delivery_task_store SET del_flag = 1 WHERE delivery_task_id = ? AND store_id = ?
            boolean update = deliveryTaskTemplateStoreService.update(deliveryTaskTemplateStore, updateWrapper);
            if (!update) {
                // 如果更新失败，向前端返回错误提示信息
                throw new ModifyFailureException("新增配送任务与店铺关联失败，请稍后重试");
            }
        } else {
            // 如果关联关系不存在，则新增关联关系
            DeliveryTaskTemplateStore deliveryTaskTemplateStore = new DeliveryTaskTemplateStore();
            deliveryTaskTemplateStore.setTaskTemplateId(taskId);
            deliveryTaskTemplateStore.setStoreId(storeId);
            deliveryTaskTemplateStore.setDelFlag(false);

            boolean save = deliveryTaskTemplateStoreService.save(deliveryTaskTemplateStore);
            if (!save) {
                // 如果新增失败，向前端返回错误提示信息
                throw new ModifyFailureException("新增配送任务与店铺关联失败，请稍后重试");
            }
        }
    }


    @Transactional(rollbackFor = {ModifyFailureException.class})
    public void deleteDeliveryTaskById(String taskTemplateId) {
        DeliveryTaskTemplate savedDeliveryTaskTemplate = deliveryTaskTemplateMapper.selectById(taskTemplateId);
        // 校验前端传递的参数是否合法
        if (savedDeliveryTaskTemplate == null) {
            throw new IllegalArgumentException("ID 为 " + taskTemplateId + " 的配送任务模板不存在");
        }
        // 如果配送任务已经删除，则不需要进行任何操作
        if (savedDeliveryTaskTemplate.getDelFlag()) {
            return;
        }

        // 将指定配送任务的 del_flag 标志置为 1
        DeliveryTaskTemplate deliveryTaskTemplate = new DeliveryTaskTemplate();
        deliveryTaskTemplate.setId(taskTemplateId);
        deliveryTaskTemplate.setDelFlag(true);
        int updateCount = deliveryTaskTemplateMapper.updateById(deliveryTaskTemplate);
        if (updateCount != 1) {
            // 更新失败时回滚数据，并向前端返回错误提示信息
            throw new ModifyFailureException("删除配送任务失败，请稍后重试");
        }

        // 将与该配送任务关联的取餐店铺信息记录全部置为已删除状态
        LambdaUpdateWrapper<DeliveryTaskTemplateStore> updateWrapper = new LambdaUpdateWrapper<DeliveryTaskTemplateStore>()
                .eq(DeliveryTaskTemplateStore::getTaskTemplateId, taskTemplateId)
                .eq(DeliveryTaskTemplateStore::getDelFlag, false);
        DeliveryTaskTemplateStore deliveryTaskTemplateStore = new DeliveryTaskTemplateStore();
        deliveryTaskTemplateStore.setDelFlag(true);

        boolean update = deliveryTaskTemplateStoreService.update(deliveryTaskTemplateStore, updateWrapper);
        if (!update) {
            // 更新失败时回滚数据，并向前端返回错误提示信息
            throw new ModifyFailureException("删除配送任务失败，请稍后重试");
        }

        // 如果删除配送任务模板时，当前时间在配送开始时间之前，则需要删除当日的配送任务
        String deliveryStartTime = savedDeliveryTaskTemplate.getDeliveryStartTime();
        if (isCurrentTimeBeforeDeliveryStartTime(deliveryStartTime)) {
            String currentDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            LambdaQueryWrapper<DeliveryTask> queryWrapper = new LambdaQueryWrapper<DeliveryTask>()
                    .eq(DeliveryTask::getTaskTemplateId, taskTemplateId)
                    .eq(DeliveryTask::getDeliveryDate, currentDate)
                    .eq(DeliveryTask::getDelFlag, false);
            // 每个配送任务模板每天有且仅有一个未删除的配送任务
            DeliveryTask deliveryTask = deliveryTaskMapper.selectOne(queryWrapper);
            if (deliveryTask != null) {
                softDeleteDeliveryTask(deliveryTask.getId());
            }
        }

        // 删除可能存在的明天的配送任务
        String tomorrowDate = DateTimeUtil.getTomorrowDate();
        LambdaQueryWrapper<DeliveryTask> queryWrapper = new LambdaQueryWrapper<DeliveryTask>()
                .eq(DeliveryTask::getTaskTemplateId, taskTemplateId)
                .eq(DeliveryTask::getDeliveryDate, tomorrowDate)
                .eq(DeliveryTask::getDelFlag, false);
        // 每个配送任务模板每天有且仅有一个未删除的配送任务
        DeliveryTask deliveryTask = deliveryTaskMapper.selectOne(queryWrapper);
        if (deliveryTask != null) {
            softDeleteDeliveryTask(deliveryTask.getId());
        }
    }


    public List<CooperatingCompanyVO> queryCooperatingCompanyList(String tenantId) {
        // SELECT * FROM company WHERE tenant_id = #{tenantId} AND del_flag = false
        LambdaQueryWrapper<Company> queryWrapper = new LambdaQueryWrapper<Company>()
                .eq(Company::getTenantId, tenantId)
                .eq(Company::getDelFlag, false);
        List<Company> companyList = companyMapper.selectList(queryWrapper);

        return companyList.stream()
                .map(company -> new CooperatingCompanyVO(company.getId(), company.getName()))
                .collect(Collectors.toList());
    }


    public RiderMealTypeCascadeVO queryRiderStoreCascade(String tenantId, String companyId) {
        Company company = companyMapper.selectById(companyId);
        if (company == null) {
            throw new IllegalArgumentException("ID " + companyId + " 的公司不存在");
        }

        String mealsConfig = (company.getMealsConfig() != null && !company.getMealsConfig().isEmpty()) ? company.getMealsConfig() : "[]";
        List<MealConfig> mealTypes = JSONObject.parseArray(mealsConfig, MealConfig.class);
        // 将数据库中保存的用餐时段（英文）名称转换成对应的中英文键值对
        List<MealTypeWithNameVO> selectedMealTypeList = mealTypes.stream()
                .filter(MealConfig::getEnabled)
                .map(MealConfig::getMealType)
                .map(this::buildMealTypeWithNameVO)
                .collect(Collectors.toList());

        // 查询未删除的共享骑手或隶属于 tenantId 租户的骑手
        // SELECT * FROM delivery_rider WHERE del_flag = 0 AND (tenant_id = #{tenantId} OR type = 2)
        LambdaQueryWrapper<DeliveryRider> riderQueryWrapper = new LambdaQueryWrapper<DeliveryRider>()
                .eq(DeliveryRider::getDelFlag, false)
                .and(wrapper -> wrapper.eq(DeliveryRider::getTenantId, tenantId)
                        .or()
                        .eq(DeliveryRider::getType, 2)
                );
        List<DeliveryRider> riders = riderMapper.selectList(riderQueryWrapper);
        List<RiderIdWithNameVO> riderVOList = riders.stream()
                .map(rider -> new RiderIdWithNameVO(rider.getId(), rider.getName()))
                .collect(Collectors.toList());

        RiderMealTypeCascadeVO vo = new RiderMealTypeCascadeVO();
        vo.setMealTypeList(selectedMealTypeList);
        vo.setRiderList(riderVOList);
        return vo;
    }

    private MealTypeWithNameVO buildMealTypeWithNameVO(String mealTypeEn) {
        for (MealTypeEnum enumValue : MealTypeEnum.values()) {
            if (enumValue.getMealTypeEn().equals(mealTypeEn)) {
                return new MealTypeWithNameVO(enumValue.getMealTypeCn(), enumValue.getMealTypeEn());
            }
        }
        // 如果找不到对应的枚举值，说明数据库中保存的用餐时段数据异常
        throw new IllegalArgumentException("数据异常，找不到 " + mealTypeEn + "，请联系管理员排查");
    }


    public List<StoreIdWithNameVO> queryStoreListCascade(String companyId, String mealType) {
        // 查询为该公司供餐的未删除的店铺 ID 列表，
        // SELECT store_id FROM food_menu
        // WHERE del_flag = 0 AND company_id = #{companyId} AND tenant_id = #{tenantId} AND marker = 2;
        LambdaQueryWrapper<FoodMenu> foodMenuQueryWrapper = new LambdaQueryWrapper<FoodMenu>()
                .eq(FoodMenu::getDelFlag, false)
                .eq(FoodMenu::getCompanyId, companyId)
                .eq(FoodMenu::getMealType, mealType)
                // food_menu 表中存在歧义数据（脏数据），按理说每个 marker 为 2 的记录都应该有 tenant_id，但实际表现是有的有，有的没有（多租户版本上线时历史数据迁移未完全设置 tenant_id）
                // 一个公司有且仅有一个 tenant 负责，所以不加 tenant_id 条件，应该也是等效的
                // .eq(FoodMenu::getTenantId, tenantId)
                .eq(FoodMenu::getMarker, 2)
                .select(FoodMenu::getStoreId);
        List<String> storeIds = foodMenuMapper.selectObjs(foodMenuQueryWrapper);
        // 去重
        List<String> distinctStoreIdList = storeIds.stream()
                .distinct()
                .collect(Collectors.toList());
        // 如果去重后的店铺 ID 列表为空，则说明改公司在当前用餐时段没有供餐的店铺
        if (distinctStoreIdList.isEmpty()) {
            // 直接返回空的店铺列表接口
            return new ArrayList<>();
        }

        // 如果去重后的店铺 ID 列表不为空
        // 根据店铺 ID 列表，查询未删除的店铺信息
        LambdaQueryWrapper<Store> storeQueryWrapper = new LambdaQueryWrapper<Store>()
                .eq(Store::getDelFlag, false)
                .in(Store::getId, distinctStoreIdList);
        List<Store> storeList = storeMapper.selectList(storeQueryWrapper);
        // 转换成前端需要的格式（店铺 ID 和店铺名称键值对列表）
        return storeList.stream()
                .map(StoreIdWithNameVO::new)
                .collect(Collectors.toList());
    }
}
